package com.cn.fw4j.util.rhino;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cn.fw4j.util.PropertiesHelper;
import com.cn.fw4j.util.StreamHelper;

/**
 * Rhino javascript 引擎操作的封装
 * @author 穆仁超
 */
public class JSHelper {
	private final static Logger logger = LoggerFactory.getLogger(JSHelper.class);
	
	private static boolean FW4J_JS_CACHE = true;
	private final static Map<String,String> cache = new HashMap<String,String>();
	private Context cx;
	private Scriptable scope;
	
	static{
		String val = PropertiesHelper.get("fw4j.properties", "FW4J_JS_CACHE");
		if(val != null){
			FW4J_JS_CACHE = Boolean.parseBoolean(val);
		}
	}
	
	public JSHelper(){
		cx = Context.enter();
		scope = cx.initStandardObjects();
	}
	
	public JSHelper(String filename){
		cx = Context.enter();
		scope = cx.initStandardObjects();
		load(filename);
	}
	
	/**
	 * 根据文件名加载js文件
	 * @param filename String 文件名
	 */
	public void load(String filename){
		try {
			String script = null;
			if(cache.containsKey(filename) && FW4J_JS_CACHE){
				script = cache.get(filename);
			}else{
				InputStream input = StreamHelper.getInputStreamByFileName(filename);
				script = StreamHelper.getContent(input);
				cache.put(filename, script);
			}
			cx.evaluateString(scope, script, null, 1, null);
			logger.info("load "+filename);
		} catch (IOException e) {
			Context.exit();
			e.printStackTrace();
		}
	}
	
	/**
	 * 加载多个js文件
	 * @param filename
	 */
	public void loads(String[] filename){
		for(String name : filename){
			load(name);
		}
	}
	
	/**
	 * 加载js源码
	 * @param source
	 */
	public void loadSource(String source){
		cx.evaluateString(scope, source, null, 1,null);
	}
	
	public JSField getField(String name){
		return new JSField(name,scope);
	}
	
	public JSMethod getMethod(String name){
		return new JSMethod(name, cx, scope);
	}
	
	public Context getCx() {
		return cx;
	}

	public Scriptable getScope() {
		return scope;
	}
}
